home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 March: Reference Library / Dev.CD Mar 96 RL / Dev.CD Mar 96 RL.toast / Technical Documentation / develop / develop Issue 25 / develop Issue 25 code / Display Manager Sample / displays.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-19  |  11.8 KB  |  483 lines  |  [TEXT/CWIE]

  1. /***********************************************************************
  2. #
  3. #        displays.c
  4. #
  5. #        This segment handles the Display Manager notification and
  6. #        repositions application windows in response.
  7. #
  8. #        Author: Michael Marinkovich
  9. #                Apple Developer Technical Support
  10. #
  11. #
  12. #        Modification History: 
  13. #
  14. #            10/12/95    MWM     Initial coding                     
  15. #
  16. #
  17. #        Copyright © 1992-95 Apple Computer, Inc., All Rights Reserved
  18. #
  19. #
  20. ***********************************************************************/
  21.  
  22. #include <Events.h>
  23. #include <ToolUtils.h>
  24. #include <Gestalt.h>
  25. #include <OSUtils.h>
  26.  
  27.  
  28. #include "App.h"
  29. #include "Proto.h"
  30.  
  31.  
  32. //----------------------------------------------------------------------
  33. //
  34. //    InstallDMNotification - tell DM that we want to be notified by callback.
  35. //                      
  36. //                      
  37. //----------------------------------------------------------------------
  38.  
  39. OSErr InstallDMNotification(void)
  40. {
  41.     OSErr                    err;
  42.     ProcessSerialNumber        thePSN;
  43.     DMNotificationUPP        DMNUPP;
  44.     
  45.     // use our process number so when we get called
  46.     // the A5 is ours
  47.     err = GetCurrentProcess(&thePSN);
  48.     
  49.     if (err == noErr) {
  50.         DMNUPP = NewDMNotificationProc(WorldChangedProc);
  51.         err = DMRegisterNotifyProc(DMNUPP, &thePSN);
  52.     }
  53.     
  54.     return err;
  55.     
  56. }    
  57.  
  58.  
  59. //----------------------------------------------------------------------
  60. //
  61. //    InstallAEDMNotification - tell DM that we want to be notified by AE.
  62. //                      
  63. //                      
  64. //----------------------------------------------------------------------
  65.  
  66. OSErr InstallAEDMNotification(void)
  67. {
  68.     OSErr        err;
  69.     
  70.     err = AEInstallEventHandler(kCoreEventClass, kAESystemConfigNotice,
  71.                                 NewAEEventHandlerProc(DoAEDisplayUpdate),
  72.                                 0L, false);
  73.  
  74.     return err;
  75.  
  76. }
  77.  
  78.  
  79. //----------------------------------------------------------------------
  80. //
  81. //    RemoveDMNotification - tell DM that we no longer want to be notified.
  82. //                      
  83. //                      
  84. //----------------------------------------------------------------------
  85.  
  86. OSErr RemoveDMNotification(void)
  87. {
  88.     OSErr                    err;
  89.     ProcessSerialNumber        thePSN;
  90.     DMNotificationUPP        DMNUPP;
  91.     
  92.     err = GetCurrentProcess(&thePSN);
  93.     
  94.     if (err == noErr) {
  95.         DMNUPP = NewDMNotificationProc(WorldChangedProc);
  96.         err = DMRemoveNotifyProc(DMNUPP, &thePSN);
  97.     }
  98.     
  99.     return err;
  100.     
  101. }
  102.  
  103.  
  104. //----------------------------------------------------------------------
  105. //
  106. //    WorldChangedProc - Display Manager calls this proc when a depth or  
  107. //                       mode change is made. Your application should
  108. //                       handle window repositioning here. 
  109. //----------------------------------------------------------------------
  110.  
  111. pascal OSErr WorldChangedProc(AppleEvent *event)
  112. {
  113.     OSErr                    err;
  114.  
  115.     err = HandleNotification(event);
  116.     
  117.     return noErr;
  118.     
  119. }
  120.  
  121.  
  122. //----------------------------------------------------------------------
  123. //
  124. //    DoAEDisplayUpdate - Display Manager calls this proc when a depth or  
  125. //                        mode change is made. Your application should
  126. //                        handle window repositioning here. 
  127. //----------------------------------------------------------------------
  128.  
  129. pascal OSErr DoAEDisplayUpdate(AppleEvent event,AppleEvent reply,long refCon)
  130. {
  131.     OSErr                    err;
  132.  
  133.     err = HandleNotification(&event);
  134.  
  135.     return noErr;
  136.     
  137. }
  138.  
  139.  
  140. //----------------------------------------------------------------------
  141. //
  142. //    HandleNotification - handle the AppleEvent returned by either the 
  143. //                           callback or the AppleEvent procedure.
  144. //                      
  145. //----------------------------------------------------------------------
  146.  
  147. OSErr HandleNotification(AppleEvent *event)
  148. {
  149.     OSErr                    err;
  150.     GrafPtr                    oldPort;
  151.     AEDescList                displayList;
  152.     AEDescList                aDisplay;
  153.     AERecord                oldConfig,newConfig;
  154.     AEKeyword                tempWord;
  155.     DisplayIDType            displayID;
  156.     unsigned long            returnType;
  157.     long                    count;
  158.     Rect                    oldRect, newRect;
  159.     
  160.     GetPort(&oldPort);
  161.  
  162.     // Get a list of the displays from the Display Notice AppleEvent.
  163.     err = AEGetParamDesc(event,kAEDisplayNotice,typeWildCard,&displayList);
  164.     // How many items in the list
  165.     err = AECountItems(&displayList,&count);
  166.     
  167.     while (count > 0) {     // Loop through the list.
  168.         err = AEGetNthDesc(&displayList, count, typeWildCard, &tempWord, 
  169.                                     &aDisplay);
  170.         
  171.         // Get the Old Rect.            
  172.         err = AEGetNthDesc(&aDisplay, 1, typeWildCard, &tempWord, 
  173.                            &oldConfig);
  174.         err = AEGetKeyPtr(&oldConfig, keyDeviceRect, typeWildCard, 
  175.                           &returnType, &oldRect, 8, nil);
  176.         
  177.         // Get the DisplayID so we can get the GDevice later.                
  178.         err = AEGetKeyPtr(&oldConfig, keyDisplayID, typeWildCard, 
  179.                           &returnType, &displayID, 8, nil);
  180.  
  181.         // Get the New Rect.                
  182.         err = AEGetNthDesc(&aDisplay, 2, typeWildCard, &tempWord, 
  183.                            &newConfig);
  184.         err = AEGetKeyPtr(&newConfig, keyDeviceRect, typeWildCard, 
  185.                           &returnType, &newRect, 8, nil);
  186.         
  187.         // If the New and Old rects are not the same then we can assume
  188.         // the GDevice has changed and we need to rearrange the windows.
  189.         if (err == noErr && !EqualRect(&newRect, &oldRect))
  190.             HandleDeviceChange(displayID, &newRect);
  191.  
  192.         count--;
  193.         err = AEDisposeDesc(&aDisplay);
  194.         err = AEDisposeDesc(&oldConfig);
  195.         err = AEDisposeDesc(&newConfig);
  196.  
  197.     }
  198.     
  199.     err = AEDisposeDesc(&displayList);
  200.     SetPort(oldPort);
  201.     
  202.     return err;
  203. }
  204.  
  205.  
  206. //----------------------------------------------------------------------
  207. //
  208. //    HandleDeviceChange - called when the oldconfig is different from 
  209. //                         newconfig. Will check all windows on effected 
  210. //                           device and move if needed.
  211. //----------------------------------------------------------------------
  212.  
  213. OSErr HandleDeviceChange(DisplayIDType displayID, Rect *newRect)
  214. {
  215.     OSErr        err = noErr;
  216.     GDHandle    gd;
  217.     GDHandle    onGD;
  218.     WindowRef    window;
  219.     
  220.     // Get the GDevice from the DisplayID.
  221.     err = DMGetGDeviceByDisplayID((DisplayIDType) displayID, &gd, false);
  222.  
  223.     if (err == noErr && gd != nil) {
  224.         window = FrontWindow();
  225.         
  226.         while (window != nil) {
  227.             SetPort(window); 
  228.             // which device holds the greatest portion of the window
  229.             onGD = GetGreatestDevice(window);
  230.             
  231.             // If the window is not 50% or greater on
  232.             // the desired device then pass it up.
  233.             if (onGD == gd) { 
  234.                 if (OutOfBoundsRect(gd, window, *newRect)) {
  235.                     MoveInbounds(window, gd, *newRect); 
  236.                     if (OutOfBoundsRect(gd, window, *newRect)) {
  237.                         ResizeInbounds(window, gd, *newRect);
  238.                         
  239.                         // If it is one of our document windows then we need
  240.                         // to reset the std state and the scroll bars.
  241.                         if (GetIsAppWindow(window))
  242.                             AdjustScrollbars(window, true);
  243.                     }        
  244.                 }
  245.                 ResetStdState(window);
  246.  
  247.             }    
  248.             window = (WindowRef)(((WindowPeek)window)->nextWindow);
  249.         }
  250.     }
  251.     
  252.     return err;
  253.     
  254. }
  255.  
  256.     
  257. //----------------------------------------------------------------------
  258. //
  259. //    OutOfBoundsRect -  check to see if the window is out of the device
  260. //                       rect.
  261. //                      
  262. //----------------------------------------------------------------------
  263.  
  264. Boolean OutOfBoundsRect(GDHandle gd, WindowRef window, Rect screenRect)
  265. {
  266.     Boolean        out = false;
  267.     Rect        windRect;
  268.     short        mHeight = 0;
  269.     
  270.     GetWindowRect(window, &windRect);
  271.     
  272.     if (gd == GetMainDevice())
  273.         mHeight = GetMBarHeight();
  274.  
  275.     if ((windRect.right > screenRect.right) || (windRect.bottom > screenRect.bottom))
  276.         out = true;
  277.  
  278.     if ((windRect.left < screenRect.left) || (windRect.top < screenRect.top + mHeight))
  279.         out = true;
  280.     
  281.     return out;
  282.     
  283. }
  284.     
  285.     
  286. //----------------------------------------------------------------------
  287. //
  288. //    MoveInbounds -  Move window on to desired device
  289. //                        
  290. //                      
  291. //----------------------------------------------------------------------
  292.  
  293. void MoveInbounds(WindowRef window, GDHandle gd, Rect screenRect)
  294. {
  295.     Rect        bounds;
  296.     short        mHeight = 0;
  297.     short        hGlobal;
  298.     short        vGlobal;
  299.         
  300.     GetWindowRect(window, &bounds);
  301.  
  302.     if (gd == GetMainDevice())
  303.         mHeight = GetMBarHeight();
  304.         
  305.     hGlobal = bounds.left;
  306.     vGlobal = bounds.top + kTitleBarHeight;
  307.     
  308.     // we want to make the left-top a priority so adjust it first
  309.     // as to override the bottom, right movements. This is so we
  310.     // can resize the window later. 
  311.     
  312.     if (((bounds.right - bounds.left) > (screenRect.right - screenRect.left)) ||
  313.         ((bounds.bottom - bounds.top) > 
  314.         ((screenRect.bottom - screenRect.top) - mHeight))) {
  315.         
  316.         // adjust left
  317.         if (bounds.left < screenRect.left)
  318.             hGlobal = screenRect.left + kFudgeFactor;
  319.         
  320.         // adjust top
  321.         if (bounds.top < screenRect.top + mHeight)
  322.             vGlobal = screenRect.top + kTitleBarHeight + mHeight + kFudgeFactor;
  323.  
  324.     }    
  325.     else {
  326.         // adjust left
  327.         if (bounds.left < screenRect.left)
  328.             hGlobal = screenRect.left + kFudgeFactor;
  329.         else {
  330.             // adjust right
  331.             if (bounds.right > screenRect.right)
  332.                 hGlobal = (screenRect.right - (bounds.right - bounds.left)) - kFudgeFactor;
  333.         }
  334.         
  335.         // adjust top
  336.         if (bounds.top < screenRect.top + mHeight)
  337.             vGlobal = screenRect.top + kTitleBarHeight + mHeight + kFudgeFactor;
  338.  
  339.         else {
  340.             // adjust bottom
  341.             if (bounds.bottom > screenRect.bottom)
  342.                 vGlobal = (screenRect.bottom -  kFudgeFactor -
  343.                           (bounds.bottom - bounds.top) + mHeight);
  344.         }        
  345.  
  346.     }
  347.     
  348.     MoveWindow(window, hGlobal, vGlobal,false);
  349.         
  350. }
  351.     
  352.  
  353. //----------------------------------------------------------------------
  354. //
  355. //    ResizeInbounds -  resize the window to fit in the graphics device
  356. //                        
  357. //                      
  358. //----------------------------------------------------------------------
  359.  
  360. void ResizeInbounds(WindowRef window, GDHandle gd, Rect screenRect)
  361. {
  362.     Rect        windRect;
  363.     short        h;
  364.     short        v;
  365.  
  366.     //GetWindowRect(window, &windRect);
  367.  
  368.     windRect = window->portRect;
  369.     // make the window bounds the size of the gdRect
  370.     // less the fudge factor.
  371.     h = windRect.right - windRect.left;
  372.     v = windRect.bottom - windRect.top;
  373.  
  374.     if (h > screenRect.right - screenRect.left)
  375.         h = ((screenRect.right - screenRect.left) - (kFudgeFactor * 2));
  376.     
  377.     if (v > screenRect.bottom - screenRect.top) {
  378.         v = ((screenRect.bottom - screenRect.top) - (kFudgeFactor * 2));
  379.         
  380.         // If we are on the main device then subtract the mBar
  381.         // height plus a fudge factor for a boundary. 
  382.         if (gd == GetMainDevice())
  383.             v -= (GetMBarHeight() + kTitleBarHeight);
  384.     }        
  385.  
  386.         
  387.     SizeWindow(window, h, v, true);
  388.  
  389. }
  390.     
  391.  
  392. //----------------------------------------------------------------------
  393. //
  394. //    GetGreatestDevice - find thw device that holds the greatest area 
  395. //                        of the window.
  396. //                      
  397. //----------------------------------------------------------------------
  398.  
  399. GDHandle GetGreatestDevice(WindowRef window)
  400. {
  401.     GDHandle    gd;
  402.     GDHandle    savedGD;
  403.     Rect        gdRect;
  404.     Rect        foundRect;
  405.     long        size;
  406.     long        greatest = nil;
  407.  
  408.     gd = DMGetFirstScreenDevice(dmOnlyActiveDisplays);
  409.     savedGD = gd;
  410.     
  411.     // Loop through the device list
  412.     while (gd != nil) {    
  413.         gdRect = (**gd).gdRect;
  414.         
  415.         GlobalToLocal(&topLeft(gdRect));
  416.         GlobalToLocal(&botRight(gdRect));
  417.         
  418.         if (SectRect(&window->portRect, &gdRect, &foundRect)) {
  419.             size = ((long)(foundRect.right - foundRect.left) * 
  420.                    (long)(foundRect.bottom - foundRect.top));
  421.             
  422.             if (size > greatest) {
  423.                 greatest = size;
  424.                 savedGD = gd;        // save the greatest device
  425.             }    
  426.         }
  427.         gd = DMGetNextScreenDevice(gd, dmOnlyActiveDisplays);
  428.     }
  429.     
  430.     return savedGD;
  431. }
  432.  
  433.  
  434. //----------------------------------------------------------------------
  435. //
  436. //    GetWindowRect - return actual window rect in global coords
  437. //                    
  438. //                    
  439. //----------------------------------------------------------------------
  440.  
  441. void GetWindowRect(WindowRef window, Rect *windRect)
  442. {    
  443.     *windRect = window->portRect;
  444.     
  445.     // add the titlebar height for actual height
  446.     windRect->top -= kTitleBarHeight;
  447.     
  448.     LocalToGlobal(&TopLeft(*windRect));
  449.     LocalToGlobal(&BotRight(*windRect));
  450.  
  451.  
  452. }
  453.  
  454. //----------------------------------------------------------------------
  455. //
  456. //    ResetStdState - since we are now on a different size screen we need
  457. //                    to change the stdState window size so our zooming
  458. //                    will work properly.  
  459. //----------------------------------------------------------------------
  460.  
  461. void ResetStdState(WindowRef window)
  462. {
  463.     Rect        screenRect;
  464.     
  465.     screenRect = window->portRect;
  466.  
  467.     LocalToGlobal(&TopLeft(screenRect));
  468.     LocalToGlobal(&BotRight(screenRect));
  469.     
  470.     // with the new interfaces we could also use the
  471.     // SetWindowStandardState procedure. 
  472.     (**(WStateDataHandle)
  473.         ((WindowPeek)window)->dataHandle).stdState = screenRect;
  474.         
  475.  
  476. }
  477.     
  478.     
  479.  
  480.     
  481.     
  482.  
  483.